#ifndef SERVERREQUESTS_H_
#define SERVERREQUESTS_H_

#include "scatu/Common.h"

namespace scatu {

/// Base class for both synchronous and asynchronous requests
class RServerRequestBase
    {
public:
    virtual void Close() = 0;
    
    void ServiceL(RMessage2 const & aMessage)
        {
        if (IsPending()) 
            { 
            PanicClient(aMessage, EPanicAlreadyRequesting); 
            return;
            }
        
        if (aMessage.Function() == iRequestId)
            {
            if (ReadyToReturn()) 
                { 
                PanicClient(aMessage, EPanicTransactionAlreadyPrepared); 
                return;
                }
            ReceiveDataL(aMessage);
            }
        else if (aMessage.Function() == RET_FUNC(iRequestId))
            {
            if (!ReadyToReturn()) 
                { 
                PanicClient(aMessage, EPanicTransactionNotPrepared); 
                return;
                }
            
            ReturnDataL(aMessage);
            }
        else
            {
            PanicClient(aMessage, EPanicIllegalFunction);
            }
        }
    
    static TLinearOrder<RServerRequestBase> LinearOrder() { return &RServerRequestBase::Compare; }
    static TInt CompareById(TInt const * aLhs, RServerRequestBase const & aRhs)
        { return *aLhs - aRhs.iRequestId; }
    
protected:
    
    RServerRequestBase(TInt aRequestId)
          : iRequestId(aRequestId)
        {}
    
    HBufC8 * ReadArgumentsLC(RMessage2 const & aMessage)
        {
        TInt length = aMessage.GetDesLengthL(EMessageSlotData);
        HBufC8* buffer = HBufC8::NewLC(length);
        TPtr8 ptr(buffer->Des());
        aMessage.Read(EMessageSlotData, ptr);
        return buffer;
        }
    
private: // pure virtual functions
    
    virtual TBool IsPending() = 0;
    virtual TBool ReadyToReturn() = 0;
    virtual void ReceiveDataL(RMessage2 const & aMessage) = 0;
    virtual void ReturnDataL(RMessage2 const & aMessage) = 0;
    
protected:
    TInt iRequestId;
    
private:
    static TInt Compare(RServerRequestBase const & aLhs, RServerRequestBase const & aRhs)
        {
        // IDs are all positive, so there should be no overflows 
        return aLhs.iRequestId - aRhs.iRequestId;
        }
    };

} // namespace scatu

#endif /* SERVERREQUESTS_H_ */
